using System;
using System.Collections.Generic;
using UnityEngine;

[AddComponentMenu("NGUI/UI/Particle2D")]
[ExecuteInEditMode]
public class Particle2D : UIWidget
{
	public enum Emitter
	{
		POINT = 0,
		CIRCLE = 1,
		RECT = 2
	}

	[HideInInspector]
	[SerializeField]
	public bool autoStart = true;

	[HideInInspector]
	[SerializeField]
	public UIAtlas atlas;

	[HideInInspector]
	[SerializeField]
	public List<string> sprites;

	[HideInInspector]
	[SerializeField]
	public bool worldSpace;

	[HideInInspector]
	[SerializeField]
	public Emitter emitter;

	[HideInInspector]
	[SerializeField]
	public float spwnRate = 0.1f;

	[HideInInspector]
	[SerializeField]
	public bool looping = true;

	[HideInInspector]
	[SerializeField]
	public float duration = 2f;

	[HideInInspector]
	[SerializeField]
	public int maxParticles = 10;

	[HideInInspector]
	[SerializeField]
	public bool playOnce;

	[HideInInspector]
	[SerializeField]
	public float emitterRadius = 100f;

	[HideInInspector]
	[SerializeField]
	public bool playContinuouslyInEditorMode;

	[HideInInspector]
	[SerializeField]
	public float minLifeTime = 1f;

	[HideInInspector]
	[SerializeField]
	public float maxLifeTime = 1f;

	[HideInInspector]
	[SerializeField]
	public float minSize = 1f;

	[HideInInspector]
	[SerializeField]
	public float maxSize = 1f;

	[HideInInspector]
	[SerializeField]
	public bool useSizeRate;

	[HideInInspector]
	[SerializeField]
	public AnimationCurve sizeRate;

	[HideInInspector]
	[SerializeField]
	public bool useVelocity;

	[HideInInspector]
	[SerializeField]
	public float minAngle = -180f;

	[HideInInspector]
	[SerializeField]
	public float maxAngle = 180f;

	[HideInInspector]
	[SerializeField]
	public float minPower = 200f;

	[HideInInspector]
	[SerializeField]
	public float maxPower = 300f;

	[HideInInspector]
	[SerializeField]
	public bool useAcceleration;

	[HideInInspector]
	[SerializeField]
	public AnimationCurve accelerationRate;

	[HideInInspector]
	[SerializeField]
	public bool useRotation;

	[HideInInspector]
	[SerializeField]
	public Vector3 minRotation = new Vector3(0f, 0f, 90f);

	[HideInInspector]
	[SerializeField]
	public Vector3 maxRotation = new Vector3(0f, 0f, 180f);

	[HideInInspector]
	[SerializeField]
	public bool useRotationRate;

	[HideInInspector]
	[SerializeField]
	public AnimationCurve rotationRateX;

	[HideInInspector]
	[SerializeField]
	public AnimationCurve rotationRateY;

	[HideInInspector]
	[SerializeField]
	public AnimationCurve rotationRateZ;

	[HideInInspector]
	[SerializeField]
	public bool useForce;

	[HideInInspector]
	[SerializeField]
	public Vector2 force = new Vector3(0f, 500f);

	[HideInInspector]
	[SerializeField]
	public bool useAnimatedColor = true;

	[HideInInspector]
	[SerializeField]
	public List<Color> colors;

	[HideInInspector]
	[SerializeField]
	public bool useGoToPosition;

	[HideInInspector]
	[SerializeField]
	public Transform travelTo;

	[NonSerialized]
	[HideInInspector]
	public Vector2 travelToPosition;

	[NonSerialized]
	[HideInInspector]
	public Vector2 ortoDirection;

	[HideInInspector]
	[SerializeField]
	public AnimationCurve travelRate;

	[HideInInspector]
	[SerializeField]
	public float ortoDistanceMin;

	[HideInInspector]
	[SerializeField]
	public float ortoDistanceMax;

	[HideInInspector]
	[SerializeField]
	public AnimationCurve ortoRate;

	private float startTime;

	private float lastGenParticleTime;

	public int curParticleIndex;

	private int _poolSize;

	private List<ParticleUnit> _objects = new List<ParticleUnit>();

	private Queue<ParticleUnit> _freeObjects = new Queue<ParticleUnit>();

	private List<ParticleUnit> _removableObjects = new List<ParticleUnit>();

	private float scaleFactor = 1.5f;

	[NonSerialized]
	private bool isStarted;

	protected bool _changed = true;

	private float currentTime;

	private float currentDeltaTime;

	public float emitterWidth
	{
		get
		{
			return base.width;
		}
		set
		{
			base.width = (int)value;
		}
	}

	public float emitterHeight
	{
		get
		{
			return base.height;
		}
		set
		{
			base.height = (int)value;
		}
	}

	public override Material material
	{
		get
		{
			return (!(atlas != null)) ? null : atlas.spriteMaterial;
		}
	}

	protected void SetPoolSize(int newSize)
	{
		if (newSize > _poolSize)
		{
			for (int i = _poolSize; i < newSize; i++)
			{
				ParticleUnit item = new ParticleUnit();
				_freeObjects.Enqueue(item);
			}
			_poolSize = newSize;
		}
	}

	public void SetSpriteName(string spriteName)
	{
		for (int i = 0; i < sprites.Count; i++)
		{
			sprites[i] = spriteName;
		}
	}

	private ParticleUnit Generate(float generateTime)
	{
		if (_freeObjects.Count <= 0)
		{
			int num = (int)((float)_poolSize * scaleFactor);
			if (num <= _poolSize)
			{
				num = _poolSize + 1;
			}
			SetPoolSize(num);
		}
		ParticleUnit particleUnit = _freeObjects.Dequeue();
		particleUnit.CreateParticleUnit(this, generateTime);
		_objects.Add(particleUnit);
		return particleUnit;
	}

	private void Remove(ParticleUnit obj)
	{
		_freeObjects.Enqueue(obj);
		_objects.Remove(obj);
	}

	public void Play()
	{
		Reset();
	}

	public void Reset()
	{
		Debug.Log("isStarted");
		isStarted = true;
		startTime = GetTime();
		lastGenParticleTime = startTime - spwnRate;
		curParticleIndex = 0;
		foreach (ParticleUnit @object in _objects)
		{
			_freeObjects.Enqueue(@object);
		}
		_objects.Clear();
	}

	public void AddRemovableObject(ParticleUnit unit)
	{
		_removableObjects.Add(unit);
	}

	private void ClearRemovableObjects()
	{
		for (int num = _removableObjects.Count - 1; num >= 0; num--)
		{
			Remove(_removableObjects[num]);
		}
		_removableObjects.Clear();
	}

	protected override void OnStart()
	{
		base.OnStart();
		if (!looping)
		{
			float num = duration / spwnRate;
			if (num > 1f)
			{
				num = 1f;
			}
			int num2 = (int)((float)maxParticles * num);
			num2 = ((num2 <= 0) ? 1 : num2);
			SetPoolSize(num2);
		}
		else if (maxLifeTime > spwnRate)
		{
			SetPoolSize((int)(maxLifeTime / spwnRate));
		}
		else
		{
			SetPoolSize(1);
		}
	}

	protected override void OnEnable()
	{
		base.OnEnable();
		if (autoStart || !Application.isPlaying)
		{
			Reset();
		}
	}

	protected override void OnDisable()
	{
		base.OnDisable();
	}

	private float GetTime()
	{
		return Time.time;
	}

	private float GetDeltaTime()
	{
		return Time.deltaTime;
	}

	private void GenerateParticle()
	{
		float num = currentTime - maxLifeTime;
		if (num > lastGenParticleTime)
		{
			lastGenParticleTime = num;
		}
		while (lastGenParticleTime + spwnRate <= currentTime)
		{
			lastGenParticleTime += spwnRate;
			if (curParticleIndex >= maxParticles)
			{
				break;
			}
			Generate(lastGenParticleTime);
			curParticleIndex++;
		}
	}

	private void GenerateLoopingParticle()
	{
		float num = currentTime - maxLifeTime;
		if (num > lastGenParticleTime)
		{
			lastGenParticleTime = num;
		}
		while (lastGenParticleTime + spwnRate <= currentTime)
		{
			lastGenParticleTime += spwnRate;
			Generate(lastGenParticleTime);
			curParticleIndex++;
		}
	}

	protected override void OnUpdate()
	{
		base.OnUpdate();
		currentTime = GetTime();
		currentDeltaTime = GetDeltaTime();
		if ((Application.isPlaying && !isStarted) || atlas == null || atlas.texture == null || sprites.Count <= 0)
		{
			return;
		}
		if (!looping)
		{
			if (currentTime >= startTime + duration && (!playOnce || !Application.isPlaying))
			{
				startTime = currentTime;
				lastGenParticleTime = startTime - spwnRate;
				curParticleIndex = 0;
			}
			GenerateParticle();
		}
		else
		{
			GenerateLoopingParticle();
		}
		mChanged = true;
	}

	public override void OnFill(BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
	{
		if (!isStarted)
		{
			return;
		}
		if (travelTo != null)
		{
			travelToPosition = base.transform.InverseTransformPoint(travelTo.position);
			ortoDirection = new Vector2(travelToPosition.y, 0f - travelToPosition.x).normalized;
		}
		foreach (ParticleUnit @object in _objects)
		{
			if (@object.UpdateParticleUnit(this, currentTime, currentDeltaTime))
			{
				SimpleFill(geometry.verts, geometry.uvs, geometry.cols, @object.texCoordsOuter, @object.texCoordsInner, @object);
			}
		}
		ClearRemovableObjects();
	}

	public string GetSpriteNameRandomly()
	{
		return sprites[UnityEngine.Random.Range(0, sprites.Count)];
	}

	public Color GetColor(float t)
	{
		float num = 1f / (float)(colors.Count - 1);
		int num2 = (int)(t / num);
		return Color.Lerp(colors[num2], colors[num2 + 1], (t - num * (float)num2) / num);
	}

	private void SimpleFill(BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols, Rect outer, Rect inner, ParticleUnit unit)
	{
		float num = (float)unit.spriteData.width * unit.scale.x * unit.localScale.x;
		float num2 = (float)unit.spriteData.height * unit.scale.y * unit.localScale.y;
		float num3 = 0f - num * 0.5f;
		float num4 = 0f - num2 * 0.5f;
		float x = num3 + num;
		float y = num4 + num2;
		Vector2 v = new Vector2(num3, num4);
		Vector2 v2 = new Vector2(num3, y);
		Vector2 v3 = new Vector2(x, y);
		Vector2 v4 = new Vector2(x, num4);
		RotateVertex(ref v, ref v2, ref v3, ref v4, unit.localRotation);
		Vector2 vector = (Vector2)base.transform.InverseTransformPoint(unit.distanceFromParticle2D + base.transform.position) + unit.localPosition;
		v += vector;
		v2 += vector;
		v3 += vector;
		v4 += vector;
		verts.Add(v);
		verts.Add(v2);
		verts.Add(v3);
		verts.Add(v4);
		Vector4 vector2 = new Vector4(outer.xMin, outer.yMin, outer.xMax, outer.yMax);
		uvs.Add(new Vector2(vector2.x, vector2.y));
		uvs.Add(new Vector2(vector2.x, vector2.w));
		uvs.Add(new Vector2(vector2.z, vector2.w));
		uvs.Add(new Vector2(vector2.z, vector2.y));
		Color32 item = unit.color * mColor;
		cols.Add(item);
		cols.Add(item);
		cols.Add(item);
		cols.Add(item);
	}

	private void RotateVertex(ref Vector2 v0, ref Vector2 v1, ref Vector2 v2, ref Vector2 v3, Quaternion q)
	{
		v0 = q * v0;
		v1 = q * v1;
		v2 = q * v2;
		v3 = q * v3;
	}
}
